/*
  Process Manager header file.
  Author(s):
    David Dumas - ddumas@nmt.edu
    Hakan Akkan - hkn@hakanakkan.com
*/


#ifndef H_PM
#define H_PM

#define MAX_PROCS 1000 // We use a fixed number until we implement a mm
#define N_PROC_BUCKETS 13 // A small prime number
#define MAX_COMMAND_LENGTH 56

#define NUM_PROC 1

#include <sched.h>
#include <mm.h>

typedef enum {R_FILE,R_DEV /*....*/} resource_type;

struct resource_descriptor {
	resource_type type;
	/* ... */
};

typedef enum {P_NEW,P_READY,P_WAIT,P_RUNNING,P_TERMINATED} proc_state;

struct proc_stats {
	int time_allowed;
	int time_run;
	int wait_since_run;
	int wait_total;
	/* more to come */
};


/* Make sure to set pointer values to NULL during initializing new processes */
struct process {
	int pid;  // pid == 0 means it's the kernel.
	proc_state state;
	char cmd[MAX_COMMAND_LENGTH]; // e.g. "/usr/bin/ls /home/hakan"
	int register_set_id;
	int register_contents;
	int pc;
	int stack;
	int heap;
	struct sched_info sched;
	int processor_number;
	short int valid; // If valid == 0, this PCB can be reused
	struct page_table pt;
	struct proc_stats stats;
	struct process *parent;
	struct process *child;
	/* Maybe we should keep a pointer to last child too for quickly finding it?
	struct process *last_child;
	*/
	struct process *sibling;
	struct process *next_p;
	/* Do we really need this? */
	struct process *prev_p;
	struct process *next_hash_p;
	/* more to come */
};

// Until we implement a mm, we store processes in a preallocated space.
struct process procs[MAX_PROCS];

/* The hash table that processes are stored in */
struct process *procs_hash_table[N_PROC_BUCKETS];

struct queue_definition {
	int n_elements;
	struct process *head;
	struct process *tail;
};

/* Process Table function signatures */
void init_pm();
void init_process_table();
int get_pm_size();
int put_process(struct process *p);
struct process* get_process_by_pid(int pid);
struct process* remove_process(int pid);


/* Process state transition function signatures  */
struct process* new_process(int group_no, char* cmd, int pid, int n_pages);
int terminate_process(struct process* p);
int queue_to_terminated(struct process *p);
int queue_to_ready(struct process *p);
int queue_to_running(struct process *p);
int queue_to_waiting(struct process *p);

// Peak at a queue. Returns the head but does not remove it from the queue.
struct process* peak(struct queue_definition *q);

struct process* get_process_from_processor(int processor);
void change_group(struct process* p, int gr_no);
//global variables
//////////////////

//queues for each state
struct queue_definition new_queue;
struct queue_definition ready_queue;
struct queue_definition waiting_queue;
struct queue_definition terminated_queue;
//an array of pointers to running PCBs for each processor on the system
struct process *running_list[NUM_PROC];


#endif
